/*
 * Id.java
 *
 * Created on August 11, 2005, 9:54 PM
 *
 * To change this basis, choose Tools | Options and locate the basis under
 * the Source Creation and Management node. Right-click the basis and choose
 * Open. You can then make changes to the basis in the Source Editor.
 */

package com.xucia.jsponic.data;


import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import com.xucia.jsponic.datasource.DataSource;



/**
 *
 * @author Kris Zyp
 * This class represents a select query
 */
public class ObjectPath extends Identification<Object> {
	@Override
	protected Object resolveTarget() {
		throw new RuntimeException("getTarget should always be used for ObjectPath");
	}
	List<Object> pathParts = new ArrayList<Object>();
	private ObjectPath(){
	}
	public ObjectPath(ObjectId objId, List<Object> pathParts) {
		this.subObjectId = objId.subObjectId;
		this.source = objId.source;
		this.pathParts = pathParts;
	}


	public static synchronized ObjectPath idForString(String query) {
		ObjectPath objId = new ObjectPath();
		String[] parts;
		parts = query.split("/",2);
		if (parts.length < 2){
			throw new RuntimeException("All ids must be in form of datasource/objectid");
			//objId.source = DataSourceManager.getRootSource();
			//objId.subObjectId = value;
		}
		else
		{
			objId.source = DataSourceManager.getSource(parts[0]);
			objId.subObjectId= parts[1].split("[\\.\\[].*")[0];
			String remaining = parts[1].substring(objId.subObjectId.length());
			while (remaining.length() > 0) {
				if (remaining.charAt(0)=='.') {
					remaining = remaining.substring(1);
					String prop = remaining.split("[\\.\\[].*",2)[0];
					objId.pathParts.add(prop);
					remaining = remaining.substring(prop.length());
				}
				else {
					try {
						JSONArray array = (JSONArray) new JSONTokener(remaining).nextValue();
						objId.pathParts.add(array.get(0));
						remaining = remaining.substring(array.toString().length());
					} catch (JSONException e) {
						throw new RuntimeException(e);
					}
				}
			}
		}
		return objId;
	}

	
	@Override
	public Object getTarget() {
		Object target = ObjectId.idForObject(source, subObjectId).getTarget(); 
		for (Object path : pathParts) {
			if (path instanceof Integer)
				target = ((Persistable)target).get((Integer)path,(Persistable)target);
			else
				target = ((Persistable)target).get(path.toString());
		}
		return target;
	}
	public Persistable getSecondToLastTarget() {
		Object target = ObjectId.idForObject(source, subObjectId).getTarget();
		int i = 1;
		for (Object path : pathParts) {
			if (i++ < pathParts.size()) {
				if (path instanceof Integer)
					target = ((Persistable)target).get((Integer)path,(Persistable)target);
				else
					target = ((Persistable)target).get(path.toString());
			}
		}
		return (Persistable) target;
	}
	public Object getLastPath() {
		return pathParts.get(pathParts.size()-1);
	}

	private String makePathPart() {
		StringBuffer str = new StringBuffer();
		for (Object path : pathParts) {
			if (path instanceof Integer)
				str.append("[" + path + "]");
			else if (((String)path).matches("\\w[0-9\\w]*"))
				str.append("." + path);
			else
				str.append("[" + JSONObject.quote((String) path)+ "[");
		}
		return str.toString();

	}
	@Override
	public String toString(DataSource relativeSource, String relativeSubPath) {
		return super.toString(relativeSource, relativeSubPath) + makePathPart();
	}


	@Override
	public String toString() {
		return super.toString() + makePathPart();
	}
	

}
